import os

import paramiko
from sqlalchemy.orm import Session
from fastapi import HTTPException, Depends
from database import get_db
from model.cdn_config import CdnConfig
import logging

from model.certificate import Certificate
from utils.dns_util import DNSUtil

logger = logging.getLogger("fast-run")


class CdnConfigService:

    @classmethod
    def deploy_nginx(cls, domain: str, source_ip: str, deploy_nodes: list, fullchain: str, privkey: str):
        logger.info("开始部署nginx")
        #     # 构建 nginx 配置
        with open(os.path.join("template/nginx.conf"), encoding="utf8") as f:
            nginx_tmp = f.read()

        with open(os.path.join("template/ssl_default.conf"), encoding="utf8") as f:
            nginx_ssl_tmp = f.read()

        logger.info("开始分发证书")

        nginx_conf = nginx_tmp.replace("<dns-name>", domain).replace("<source-ip>", source_ip)
        nginx_ssl_conf = nginx_ssl_tmp.replace("<dns-name>", domain).replace("<source-ip>", source_ip)
        for server in deploy_nodes:
            print(server)
            # cls.deploy_to_server(domain, server, "root", nginx_conf_content=nginx_conf, fullchain=fullchain,
            #                      privkey=privkey)

            cert_dir = f"/etc/letsencrypt/live/{domain}"
            nginx_conf_path = f"/etc/nginx/conf.d/{domain}.conf"
            nginx_ssl_conf_path = f"/etc/nginx/conf.d/ssl_default.conf"
            try:
                cls.addfile_to_server(server, "root",f"{cert_dir}/fullchain.pem", fullchain )
                cls.addfile_to_server(server, "root", f"{cert_dir}/privkey.pem", privkey)
                cls.addfile_to_server(server, "root", nginx_conf_path, nginx_conf)
                cls.addfile_to_server(server, "root", nginx_ssl_conf_path, nginx_ssl_conf)
            except Exception as e:
                logger.error(f"写入失败: {e}")
            try:
                cls.restart_to_server(server, "root", "sudo nginx -t")
                cls.restart_to_server(server, "root", "sudo nginx -s reload")
            except Exception as e:
                logger.error(f"nginx 重启失败{e}")
        results = []
        # try:
        #     print("##################开始部署证书####################")
        #
        #     # 部署 nginx 配置到节点
        #     for server in deploy_nodes:
        #         out, err = CdnConfigService.deploy_to_server(
        #             domain,
        #             host=server['host'],
        #             user=server['user'],
        #             nginx_conf_path=nginx_conf_path,
        #             nginx_conf_content=nginx_conf
        #         )
        #         results.append({"host": server['host'], "nginx_out": out, "nginx_err": err})
        #
        #     # 更新部署状态
        #     cdn_config.ifDeploy = True
        #     db.add(cdn_config)
        #     db.commit()
        #     db.refresh(cdn_config)
        #
        # except Exception as e:
        #     raise HTTPException(status_code=500, detail=f"部署失败: 无法远程到节点服务器 {str(e)}")
        #
        # return {
        #     "status": "success",
        #     "message": "CDN配置已部署到所有节点",
        #     "results": results,
        #     "cdn_config": {
        #         "id": cdn_config.id,
        #         "is_deployed": cdn_config.ifDeploy
        #     }
        # }

    @classmethod
    def deploy_cdn_config(cls, cdn_config_id: int, db: Session = Depends(get_db)):
        """
        部署
        :return:
        """

        cdn_config = db.query(CdnConfig).filter(CdnConfig.id == cdn_config_id).first()
        if not cdn_config:
            raise HTTPException(status_code=404, detail="CDN配置未找到")
        cert = db.query(Certificate).filter(Certificate.domain == cdn_config.cname.domain).first()
        if not cert:
            raise HTTPException(status_code=404, detail="没有查询到证书")

        fullchain = cert.fullchain
        privkey = cert.privkey
        logger.info(cert)
        domain = cdn_config.domain

        logger.info(f"开始部署： {domain}")
        logger.info(f"验证cname是否生效")
        cname = cdn_config.cname
        origin_ip = cdn_config.originIp
        nodes = cname.nodes
        deploy_domain = cname.domain
        deploy_nodes = [node.host for node in nodes]

        logger.info(f"当前绑定cname为： {deploy_domain}")
        logger.info(f"部署节点为： {deploy_nodes}")

        if DNSUtil.has_cname(domain,deploy_domain):
            logger.info(f"{domain}已经部署cname: {deploy_domain}")
        else:
            raise HTTPException(status_code=400, detail=f"未配置cname到{deploy_domain}，请添加后再进行部署")

        if DNSUtil.verify_domain(deploy_domain, deploy_nodes):
            logger.info(f"验证完成,开始部署")
            cls.deploy_nginx(domain=domain, source_ip=origin_ip, deploy_nodes=deploy_nodes, fullchain=fullchain,
                             privkey=privkey)
        else:
            logger.info(f"dns 解析失败，请等待")
            raise HTTPException(status_code=400, detail="域名解析还未生效，请稍后再试")

        return {}


    def deploy_cdn_config(cls, cdn_config_id: int, db: Session = Depends(get_db)):
        """
        部署
        :return:
        """

        cdn_config = db.query(CdnConfig).filter(CdnConfig.id == cdn_config_id).first()
        if not cdn_config:
            raise HTTPException(status_code=404, detail="CDN配置未找到")
        cert = db.query(Certificate).filter(Certificate.domain == cdn_config.cname.domain).first()
        if not cert:
            raise HTTPException(status_code=404, detail="没有查询到证书")

        fullchain = cert.fullchain
        privkey = cert.privkey
        logger.info(cert)
        domain = cdn_config.domain

        logger.info(f"开始部署： {domain}")
        logger.info(f"验证cname是否生效")
        cname = cdn_config.cname
        origin_ip = cdn_config.originIp
        nodes = cname.nodes
        deploy_domain = cname.domain
        deploy_nodes = [node.host for node in nodes]

        logger.info(f"当前绑定cname为： {deploy_domain}")
        logger.info(f"部署节点为： {deploy_nodes}")

        if DNSUtil.has_cname(domain,deploy_domain):
            logger.info(f"{domain}已经部署cname: {deploy_domain}")
        else:
            raise HTTPException(status_code=400, detail=f"未配置cname到{deploy_domain}，请添加后再进行部署")

        if DNSUtil.verify_domain(deploy_domain, deploy_nodes):
            logger.info(f"验证完成,开始部署")
            cls.deploy_nginx(domain=domain, source_ip=origin_ip, deploy_nodes=deploy_nodes, fullchain=fullchain,
                             privkey=privkey)



        else:
            logger.info(f"dns 解析失败，请等待")
            raise HTTPException(status_code=400, detail="域名解析还未生效，请稍后再试")

        return {}

    @classmethod
    def deploy_to_server(cls, domain, host, user, nginx_conf_content, fullchain: str = None, privkey: str = None):
        """
            部署 nginx 配置和证书到远程服务器
        """
        """
            部署 nginx 配置和证书到远程服务器
            """
        result_out = ""
        result_err = ""
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

        try:
            ssh.connect(hostname=host, username=user)

            sftp = ssh.open_sftp()
            if fullchain and privkey:
                cert_dir = f"/etc/letsencrypt/live/{domain}"
                # 创建目录
                ssh.exec_command(f"sudo mkdir -p {cert_dir}")
                ssh.exec_command(f"sudo mkdir -p /var/cache/nginx/{domain}")  # 缓存目录
                # 上传 fullchain.pem
                with sftp.file(f"{cert_dir}/fullchain.pem", "w") as f:
                    f.write(fullchain)
                # 上传 privkey.pem
                with sftp.file(f"{cert_dir}/privkey.pem", "w") as f:
                    f.write(privkey)
                result_out += f"证书上传成功: {cert_dir}\n"
            logger.info("证书分发完成")

            # 1. 检查 certbot 是否安装
            stdin, stdout, stderr = ssh.exec_command("which nginx || echo not_installed")
            result = stdout.read().decode().strip()
            if "not_installed" in result:
                logger.info("nginx 未安装，正在远程安装...")
                ssh.exec_command("sudo apt-get update -y && sudo apt-get install -y nginx")
            else:
                logger.info("nginx 已安装。")

            # 上传 nginx 配置
            remote_conf_path = f"/etc/nginx/conf.d/{domain}.conf"
            with sftp.file(remote_conf_path, "w") as f:
                f.write(nginx_conf_content)
            result_out += f"Nginx 配置上传成功: {remote_conf_path}\n"

            # 测试 nginx 配置并重启 nginx
            stdin, stdout, stderr = ssh.exec_command("sudo nginx -t")
            test_out = stdout.read().decode()
            test_err = stderr.read().decode()
            if test_err:
                result_err += f"Nginx 配置测试失败: {test_err}\n"
            else:
                result_out += "Nginx 配置测试通过\n"
                ssh.exec_command("sudo nginx -s reload")
                result_out += "Nginx 已重载\n"

            sftp.close()
            ssh.close()

        except Exception as e:
            result_err += f"部署到 {host} 失败: {str(e)}\n"

        return result_out, result_err

    @classmethod
    def restart_to_server(cls, host, user, cmd):
        result_out = ""
        result_err = ""
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

        try:
            ssh.connect(hostname=host, username=user)

            ssh.exec_command(cmd)
        except Exception as e:
            result_err += f"{host} 命令执行失败: {str(e)}\n"
        finally:
            ssh.close()

        return result_out, result_err

    @classmethod
    def mkdir_to_server(cls, host, user, dir_path):
        result_out = ""
        result_err = ""
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

        try:
            ssh.connect(hostname=host, username=user)

            ssh.exec_command(f"sudo mkdir -p {dir_path}")


        except Exception as e:
            result_err += f"{host} 文件写入失败: {str(e)}\n"
        finally:
            ssh.close()

        return result_out, result_err

    @classmethod
    def addfile_to_server(cls, host, user, file_path, content):
        """
            远程写入文件
        """

        result_out = ""
        result_err = ""
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

        try:
            ssh.connect(hostname=host, username=user)

            sftp = ssh.open_sftp()
            file_dir = os.path.dirname(file_path)
            cls.mkdir_to_server(host,user,file_dir)
            with sftp.file(file_path, "w") as f:
                f.write(content)
            result_out += f"{file_path} 配置写入完成\n"
            sftp.close()
            ssh.close()

        except Exception as e:
            result_err += f"{host} 文件写入失败: {str(e)}\n"

        return result_out, result_err
